package com.dmgis.hndz.service.impl;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.dmgis.hndz.common.constant.FileContentType;
import com.dmgis.hndz.common.exception.GlobalException;
import com.dmgis.hndz.common.utils.DocxUtil;
import com.dmgis.hndz.common.utils.FileUtil;
import com.dmgis.hndz.common.utils.MinIOUtil;
import com.dmgis.hndz.mapper.Ybca01aMapper;
import com.dmgis.hndz.pojoVo.RainfallReportInVo;
import com.dmgis.hndz.service.YqService;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlCursor;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPageSz;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;


import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.dmgis.hndz.common.constant.FilePath.RAIN_FALL;

@Service
public class YqServiceImpl implements YqService {

    private static final Logger log = LoggerFactory.getLogger(YqServiceImpl.class);


    @Autowired
    private MinIOUtil minIOUtil;

//    @Value("${nginx.filepath}")
//    private String NginxPath;

    @Value("${nginx.url}")
    private String NginxUrl;

    private static int index = 1;
    private static String oldYear = "2024";

    @Autowired
    private Ybca01aMapper ybca01aMapper;

    @Override
    public String warningProductsDownload(String yjqcode) {
        return NginxUrl + "/" + yjqcode + ".jpg";
    }

    @Override
    public String generateRainfallReport(RainfallReportInVo rainfallReportInVo) throws Exception {
        // 初始化时间
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy年MM月dd日");
        Date date = sdf.parse(rainfallReportInVo.getDate());
        String dateStr = sdf3.format(date);
        String year = dateStr.substring(0, 4);

        // 文件号
        String documentNumber;
        if (year.equals(oldYear)) { // 新一年文件号数据刷新
            DecimalFormat df = new DecimalFormat("000");
            String formattedNumber = df.format(index);
            documentNumber = year + formattedNumber;
            index++;
        } else {
            oldYear = year;
            index = 1;
            DecimalFormat df = new DecimalFormat("000");
            String formattedNumber = df.format(index);
            documentNumber = year + formattedNumber;
            index++;
        }

        // 初始化文件路径
//        String templatePath = NginxPath + "/rainfall/rainfall-report-template.docx";
//        String targetPath = NginxPath + "rainfall/雨情报告" + dateStr + ".docx";
//        String targetImgPath = NginxPath + "雨情报告" + dateStr + ".jpg";

        String templateFileUrl = minIOUtil.getFileUrl(RAIN_FALL.getPath(), "rainfall-report-template.docx");
        String targetFileName="雨情报告"+dateStr+ ".docx";
        String targetImgName="雨情报告" + dateStr + ".jpg";

        // 数据处理(排序)
        Collections.sort(rainfallReportInVo.getAreaRainfall(), new Comparator<Map<String, Object>>() {
            @Override
            public int compare(Map<String, Object> o1, Map<String, Object> o2) {
                Double rainfall1 = Double.valueOf(o1.get("rainfall").toString());
                Double rainfall2 = Double.valueOf(o2.get("rainfall").toString());
                return rainfall2.compareTo(rainfall1);
            }
        });

        Collections.sort(rainfallReportInVo.getStationRainfall(), new Comparator<Map<String, Object>>() {
            @Override
            public int compare(Map<String, Object> o1, Map<String, Object> o2) {
                Double rainfall1 = Double.valueOf(o1.get("rainfall").toString());
                Double rainfall2 = Double.valueOf(o2.get("rainfall").toString());
                return rainfall2.compareTo(rainfall1);
            }
        });

        // 计算平均降雨量
        Double Rainfall = 0.0;

        for (Map map : rainfallReportInVo.getAreaRainfall()) {
            Rainfall += Double.valueOf(map.get("rainfall").toString());
        }
        Double avgRainfall = Rainfall / rainfallReportInVo.getAreaRainfall().size();

        // 下级列表
        String areaRainfall = "";
        for (Map areaMap : rainfallReportInVo.getAreaRainfall()) {
            areaRainfall += (String) areaMap.get("area") + areaMap.get("rainfall") + "mm ";
        }

        /*// 文档生成 使用poi-tl库，但是springboot版本过低和其他相关依赖版本过低导致无法使用
            // 读取模板
            XWPFTemplate template = XWPFTemplate.compile(templatePath);

            // 初始化插入数据map
            Map<String,Object> map = new HashMap<>();
            // 插入时间
            map.put("date",dateStr);
            // 插入级别
            String level;
            if (rainfallReportInVo.getAreaCode().substring(2).equals("0000")){
                level = "省";
            }else if (rainfallReportInVo.getAreaCode().substring(4).equals("00")){
                level = "市";
            }else {
                throw new RuntimeException("级别错误");
            }
            map.put("level",level);
            map.put("averageRainfall",avgRainfall);
            String areaRainfall = "";
            for (Map areaMap : rainfallReportInVo.getAreaRainfall()){
                areaRainfall += (String) areaMap.get("area") + areaMap.get("rainfall") + "mm ";
            }
            map.put("cityRainfall",areaRainfall);

            // 插入图片
            PictureRenderData img = Pictures.of(rainfallReportInVo.getImgPath()).size(550,300).create();
            map.put("img",img);

            // 插入表格
            // 表头
            List<Map<String,String>> tableList = new ArrayList<>();
            Map<String,String> map1 = new HashMap<>();
            map1.put("station1","站名");
            map1.put("rainfall1","雨量(mm)");
            map1.put("station2","站名");
            map1.put("rainfall2","雨量(mm)");
            map1.put("station3","站名");
            map1.put("rainfall3","雨量(mm)");
            tableList.add(map1);

            // 表内数据 三个一组
            for(int i =0; i < rainfallReportInVo.getStationRainfall().size(); i += 3){
                int end = Math.min(i + 3, rainfallReportInVo.getStationRainfall().size());
                Map<String,String> newMap = new HashMap<>();
                // 组内索引
                int index = 1;
                for(int j = i; j < end; j++){
                    Map<String,Object> currentMap = rainfallReportInVo.getStationRainfall().get(j);
                    for (Map.Entry<String,Object> entry : currentMap.entrySet()) {
                        String key = entry.getKey() + index;
                        newMap.put(key, (String) entry.getValue());
                    }
                    index ++;
                }
                tableList.add(newMap);
            }

            // 创建行
            List<RowRenderData> rows = new ArrayList<>(Collections.emptyList());

            // 将每行数据插入行中
            for(Map<String,String> row : tableList){
                RowRenderData s = Rows.of(row.get("station1"),row.get("rainfall1"),row.get("station2"),row.get("rainfall2"),row.get("station3"),row.get("rainfall3")).create();
                rows.add(s);
            }

            // 创建表
            TableRenderData tableRenderData = Tables.create(rows.toArray(new RowRenderData[0]));
            map.put("table",tableRenderData);

            // 插入全部数据
            template.render(map);

            // 输出文件
            template.writeAndClose(Files.newOutputStream(Paths.get(targetPath)));*/

        HttpURLConnection urlConnection=null;
        InputStream templateInputStream =null;
        ByteArrayOutputStream byteArrayOutputStream=null;
        // 采用aspose-words进行文档生成
        try {
            URL url = new URL(templateFileUrl);
            urlConnection =(HttpURLConnection) url.openConnection();
            // 设置连接主机超时（单位：毫秒)
            urlConnection.setConnectTimeout(10000);
            // 设置从主机读取数据超时（单位：毫秒)
            urlConnection.setReadTimeout(10000);

            // 读取文档流
            templateInputStream = new BufferedInputStream(urlConnection.getInputStream());
            XWPFDocument document = new XWPFDocument(templateInputStream);
            byteArrayOutputStream = new ByteArrayOutputStream();

            List<XWPFParagraph> paragraphs = document.getParagraphs();
            // 对应替换内容
            String[] placeholders = new String[]{
                    "[文件号]",
                    "[时间]",
                    "[降雨分析]",
                    "[雨量等值图]",
                    "[降雨统计表]"
            };
            String[] replacements = new String[]{
                    documentNumber,
                    dateStr,
                    rainfallReportInVo.getAreaName(),
                    avgRainfall + "mm",
                    areaRainfall
            };

            for (int i = 0; i < paragraphs.size(); i++) {
                XWPFParagraph paragraph = paragraphs.get(i);
                String text = paragraph.getText();

                System.out.println(i);
                System.out.println(text);

                DocxUtil.replaceTextInParagraph(paragraph, placeholders, replacements);


                if (StringUtils.isNotBlank(text) && text.contains(".")) {
                    XWPFRun r = paragraph.createRun();
                    r.setText(dateStr + "全省平均降雨量为" + avgRainfall + "mm。" + areaRainfall + "。");
                }

                // 插入图片
                if (StringUtils.isNotBlank(text) && text.contains("雨量等值图")) {
                    XmlCursor cursor = paragraph.getCTP().newCursor();
                    XWPFParagraph newPara = document.insertNewParagraph(cursor);
                    newPara.setAlignment(ParagraphAlignment.CENTER);//居中
                    XWPFRun newParaRun = newPara.createRun();

                    for (MultipartFile img : rainfallReportInVo.getImages()) {
                        // 插入图片
                        CTSectPr sectPr = document.getDocument().getBody().getSectPr();
                        CTPageSz pageSize = sectPr.getPgSz();
                        int pageWidth = pageSize.getW().intValue() / 25;
                        //以前高度除以25，现在高度除以50
                        int pageHeight = pageSize.getH().intValue() / 50;
                        newParaRun.addPicture(img.getInputStream(), XWPFDocument.PICTURE_TYPE_PNG, "kill.png,", Units.toEMU(pageWidth), Units.toEMU(pageHeight));
                        minIOUtil.putObject(img.getBytes(),RAIN_FALL.getPath(),targetImgName,FileContentType.PNG);
                    }
                    document.removeBodyElement(document.getPosOfParagraph(paragraph));
                }

                // 插入表格
                if (StringUtils.isNotBlank(text) && text.contains("表格")) {
//                    XWPFParagraph paragraph

                    //获取下标
                    XmlCursor cursor = paragraph.getCTP().newCursor();
                    XWPFTable table = document.insertNewTbl(cursor);
                    //添加表头
                    XWPFTableRow row_0 = table.getRow(0);
                    row_0.getCell(0).setText("站名");
                    row_0.addNewTableCell().setText("雨量(mm)");
                    row_0.addNewTableCell().setText("站名");
                    row_0.addNewTableCell().setText("雨量(mm)");
                    row_0.addNewTableCell().setText("站名");
                    row_0.addNewTableCell().setText("雨量(mm)");

                    // 添加数据
                    List<Map<String, String>> tableList = new ArrayList<>();
                    // 表内数据 三个一组
                    for (int k = 0; k < rainfallReportInVo.getStationRainfall().size(); k += 3) {
                        int end = Math.min(k + 3, rainfallReportInVo.getStationRainfall().size());
                        Map<String, String> newMap = new HashMap<>();
                        // 组内索引
                        int groupIndex = 1;
                        for (int j = k; j < end; j++) {
                            Map<String, Object> currentMap = rainfallReportInVo.getStationRainfall().get(j);
                            for (Map.Entry<String, Object> entry : currentMap.entrySet()) {
                                String key = entry.getKey() + groupIndex;
                                newMap.put(key, String.valueOf(entry.getValue()));
                            }
                            groupIndex++;
                        }
                        tableList.add(newMap);
                    }

                    for (Map<String, String> map : tableList) {
                        int a = 0;
                        XWPFTableRow dataRow = table.createRow();
                        for (int i1 = 0; i1 < map.size() / 2; i1++) {
                            dataRow.getCell(a).setText(map.get("stationName" + (i1 + 1)));
                            a++;
                            dataRow.getCell(a).setText(map.get("rainfall" + (i1 + 1)));
                            a++;
                        }
                    }
                    DocxUtil.setTableLocation(table, "center");
                    DocxUtil.setCellLocation(table, "CENTER", "center");
                    document.removeBodyElement(document.getPosOfParagraph(paragraph));
                }
            }

            // 将生成的文档保存到输出文件
            document.write(byteArrayOutputStream);

            //将生成文档存入minIO
            Map<String, String> fileMap = minIOUtil.putObject(byteArrayOutputStream.toByteArray(), RAIN_FALL.getPath(), targetFileName, FileContentType.DOCX);

            return fileMap.get("fileUrl");

        } catch (Exception e) {
            throw e;
        }finally {
            //关闭资源
            urlConnection.disconnect();
            templateInputStream.close();
            byteArrayOutputStream.close();
        }
    }


    /**
     * 根据行政编码查询预警插件
     *
     * @param code 编码
     * @return
     */
    public String selectWarningPlugin(String code){
        return ybca01aMapper.selectWarningPlugin(code);
    }


}
